package com.im

import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.io.Serializable
import java.net.DatagramPacket
import java.net.InetAddress

// 结果码
enum class ResultCode {
    ADD_FRIEND_ALLOW,               // "添加%s为好友成功。"
    ADD_FRIEND_NOT_ALLOW,           // "拒绝和你成为好友。"
    ALREADY_BE_FRIENDS,             // "已经是你的好友了。"
    FRIEND_NAME_EQUAL_SELF_NAME,    // "好友名字与自己名字相同。"
    LOGON_SUCCEEDED,                // "登录成功。"
    NETWORK_ERROR,                  // "连接服务失败，请参考使用说明。"
    PASSWORD_WRONG,                 // "密码不正确。"
    REG_SUCCEEDED,                  // "注册成功。"
    SUCCEEDED,                      // ""
    TOO_MANY_FRIENDS,               // "朋友太多了，不能再继续添加了。"
    USER_ALREADY_LOGON,             // "该用户已经登录了。"
    USER_EXISTS,                    // "该用户名已经被注册了。"
    USER_NOT_FOUND                  // "该用户尚未注册。"
}

// 协议
abstract class ImProtocol(val mType: Type): Serializable {
    // 类型
    enum class Type {
        ADD_FRIEND_REQUEST, // 添加好友请求
        ADD_FRIEND_RESULT,  // 添加好友结果
        CHAT,               // 聊天
        FRIEND_LOGON,       // 好友登录
        LOGOFF,             // 离线
        LOGON,              // 登录
        REG                 // 注册
    }

    companion object {
        const val MULTI_CHAT: String = "群发消息"        // 群发消息标志
        const val SERVER_IP: String = "192.168.3.8"   // 服务器 IP 地址
        const val SERVER_PORT: Int = 5000               // 服务器端口号

        /**
         * 将数据报包转换成协议。
         * @param data  数据报包
         * @return 协议
         */
        fun fromDatagramPacket(data: DatagramPacket): ImProtocol? {
            var pro: ImProtocol? = null
            try {
                val byteArrayInputStream = ByteArrayInputStream(data.data)
                val objectInputStream = ObjectInputStream(byteArrayInputStream)
                pro = objectInputStream.readObject() as ImProtocol?
                objectInputStream.close()
                byteArrayInputStream.close()
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return pro
        }

        /**
         * 将协议转换成数据报包。
         * @param pro   协议
         * @param ip    目标 ip 地址
         * @param port  目标端口号
         * @return 数据报包
         */
        fun toDatagramPacket(pro: ImProtocol, ip: InetAddress, port: Int): DatagramPacket? {
            val bytes: ByteArray?
            try {
                val byteArrayOutputStream = ByteArrayOutputStream()
                val objectOutputStream = ObjectOutputStream(byteArrayOutputStream)
                objectOutputStream.writeObject(pro)
                bytes = byteArrayOutputStream.toByteArray()
                objectOutputStream.close()
                byteArrayOutputStream.close()
                return DatagramPacket(bytes, bytes.size, ip, port)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return null
        }
    }
}

// 添加好友请求
class AddFriendRequest(
    val mDstUsername: String,   // 目标用户名
    val mSrcIconIndex: Int,     // 源用户头像索引
    val mSrcUsername: String    // 源用户名
): ImProtocol(Type.ADD_FRIEND_REQUEST)

// 添加好友结果
class AddFriendResult(
    val mDstIconIndex: Int,         // 目标用户头像索引
    val mDstUsername: String,       // 目标用户名
    val mResultCode: ResultCode,    // 结果码
    val mSrcUsername: String        // 源用户名
): ImProtocol(Type.ADD_FRIEND_RESULT)

// 聊天信息
class ChatInfo(
    val mContent: String,       // 内容
    val mDstUsername: String,   // 目标用户名
    val mSrcIconIndex: Int,     // 源用户头像索引
    val mSrcUsername: String,   // 源用户名
    val mTime: String,          // 生成时间
): ImProtocol(Type.CHAT)

// 好友登录通知
class FriendLogon(
    val mUsername: String       // 用户名
): ImProtocol(Type.FRIEND_LOGON)

// 离线请求
class LogoffRequest(
    val mUsername: String       // 用户名
): ImProtocol(Type.LOGOFF)

// 登录请求
class LogonRequest: ImProtocol {
    val mUserInfo: UserInfo // 用户信息

    /**
     * 构造方法。
     * @param password  密码
     * @param username  用户名
     */
    constructor(password: String, username: String): super(Type.LOGON) {
        mUserInfo = UserInfo(0, password, username)
    }
}

// 登录结果
class LogonResult: ImProtocol(Type.LOGON) {
    var mFriendCount: Int = 0                           // 好友数
    lateinit var mFriends: MutableList<UserInfo>        // 好友名列表
    lateinit var mFriendsOnline: MutableList<Boolean>   // 好友在线状态列表
    var mIconIndex: Int = -1                            // 头像索引
    var mResultCode: ResultCode = ResultCode.SUCCEEDED  // 结果码
}

// 注册请求
class RegRequest: ImProtocol {
    val mUserInfo: UserInfo // 用户信息

    /**
     * 构造方法。
     * @param iconIndex 头像索引
     * @param password  密码
     * @param username  用户名
     */
    constructor(iconIndex: Int, password: String, username: String): super(Type.REG) {
        mUserInfo = UserInfo(iconIndex, password, username)
    }
}

// 注册结果
class RegResult: ImProtocol(Type.REG) {
    var mResultCode = ResultCode.SUCCEEDED  // 结果码
}

// 用户信息
class UserInfo(
    val mIconIndex: Int,    // 头像索引
    val mPassword: String,  // 密码
    val mUsername: String,  // 用户名
): Serializable
